
package com.jacp.image.view.menu;

import java.util.ArrayList;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;

import com.jacp.image.R;

/**
 * 自定义菜单
 * 
 * @author maylian7700@126.com
 */
public class SecondaryListMenuView {

    private PopupWindow mPopup;

    private Context mContext;

    /**
     * 图片资源
     */
    private int[] mImgRes = new int[0];

    /**
     * 文字资源
     */
    private String[] mTexts = new String[0];

    /**
     * 菜单背景
     */
    private int mBg;

    /**
     * 菜单显示消失的动画
     */
    private int mAnimStyle = R.style.popup_show_out;

    /**
     * 文字大小
     */
    private float mTxtSize = -1;

    /**
     * 文字颜色
     */
    private int mTxtColor = -1;

    /**
     * 文本相对图片的对齐方式
     */
    private int mAlign = MenuItem.TEXT_BOTTOM;

    /**
     * 菜单项选中的效果
     */
    private int mSelector = -1;

    /**
     * 菜单的宽
     */
    private int mWidth;

    /**
     * 菜单的高
     */
    private int mHeight;

    /**
     * 存放菜单项
     */
    private GridView mGridView;

    /**
     * 设置文字的最大长度，超过则会以"..."替代
     */
    private int mMaxStrLength = 4;

    private boolean mIsShow = false;

    /**
     * 菜单项点击事件
     */
    private OnMenuClickListener mListener;

    /**
     * 是否对过长字符串采取优化
     */
    private boolean mIsOptimizeTxt = true;

    /**
     * 到屏幕左边的距离
     */
    private int mLeftMargin;

    /**
     * 保存菜单项
     */
    private ArrayList<MenuItem> mMenuItems = new ArrayList<MenuItem>();

    public SecondaryListMenuView(Context context) {
        if (null == context) {
            throw new IllegalStateException();
        }

        mContext = context;
    }

    /**
     * 设置图片资源
     * 
     * @param imgRes
     */
    public void setImageRes(int[] imgRes) {
        if (null != imgRes) {
            mImgRes = imgRes;
        }
    }

    /**
     * 设置菜单背景
     * 
     * @param bgRes
     */
    public void setBackgroundResource(int bgRes) {
        mBg = bgRes;
    }

    /**
     * 设置菜单项的文字
     * 
     * @param txtRes 资源数组
     */
    public void setText(int[] txtRes) {
        if (null == txtRes) {
            return;
        }

        final Resources res = mContext.getResources();
        final int length = txtRes.length;
        mTexts = new String[length];
        for (int i = 0; i < length; i++) {
            mTexts[i] = res.getString(txtRes[i]);
        }
    }

    /**
     * 设置菜单项的文字
     * 
     * @param txtRes
     */
    public void setText(String[] texts) {
        mTexts = texts;
    }

    /**
     * 设置文字大小
     * 
     * @param txtSize
     */
    public void setTextSize(float txtSize) {
        mTxtSize = txtSize;
    }

    /**
     * 设置文字颜色
     * 
     * @param color
     */
    public void setTextColor(int color) {
        mTxtColor = color;
    }

    /**
     * 设置文本相对图片的对齐方式
     * 
     * @param align
     */
    public void setTextAlign(int align) {
        mAlign = align;
    }

    /**
     * 允许文本的最大长度
     * 
     * @param length
     */
    public void setMaxTextLength(int length) {
        mMaxStrLength = length;
    }

    /**
     * 设置是否对过长文本进行优化
     * 
     * @param isOptimize
     */
    public void isOptimizeText(boolean isOptimize) {
        mIsOptimizeTxt = isOptimize;
    }

    /**
     * 设置菜单动画
     * 
     * @param animStyle
     */
    public void setAnimStyle(int animStyle) {
        mAnimStyle = animStyle;
    }

    /**
     * 设置菜单的宽度
     * 
     * @param width
     */
    public void setWidth(int width) {
        mWidth = width;
    }

    /**
     * 设置菜单的高度
     * 
     * @param height
     */
    public void setHeight(int height) {
        mHeight = height;
    }

    /**
     * 设置菜单被项被选中的效果
     * 
     * @param selector
     */
    public void setSelector(int selector) {
        mSelector = selector;
    }

    /**
     * 设置装载菜单内容的载体
     * 
     * @param view
     */
    public void setMenuConentView(GridView view) {
        mGridView = view;
    }

    /**
     * 设置间距
     * 
     * @param left
     */
    public void setMargin(int left) {
        mLeftMargin = left;
    }

    /**
     * 显示菜单
     * 
     * @return 显示成功返回true, 失败返回false
     */
    public boolean show() {
        if (hide()) {
            return false;
        }

        mIsShow = true;
        final Context context = mContext;
        final int length = mImgRes.length;
        final int txtLength = mTexts.length;
        Point point = new Point();
        if (length != 0 && txtLength != 0) {
            Point p1 = getTextMaxDimenstion(mTexts);
            Point p2 = getImageMaxDimension(mImgRes);
            switch (mAlign) {
                case MenuItem.TEXT_BOTTOM:
                case MenuItem.TEXT_TOP:
                    point.x = Math.max(p1.x, p2.x);
                    point.y = p1.y + p2.y;
                    break;
                case MenuItem.TEXT_LEFT:
                case MenuItem.TEXT_RIGHT:
                    point.x = p1.x + p2.x;
                    point.y = Math.max(p1.y, p2.y);
                    break;
            }
        } else {
            if (length != 0) {
                point = getImageMaxDimension(mImgRes);
            } else if (txtLength != 0) {
                point = getTextMaxDimenstion(mTexts);
            }
        }

        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        int width = mWidth == 0 ? metrics.widthPixels : mWidth;
        float density = metrics.density;
        int imgWidth = point.x;
        int height = point.y;
        // 除去5dp的间距一行所能摆放图片的个数
        int columns = (int)((width - 5 * density) / (imgWidth + 5 * density));

        int leng = length != 0 ? length : txtLength;
        int rows = columns == 0 ? 0 : leng / columns;
        if (columns * rows < leng) {
            rows += 1;
        }

        final LinearLayout layout = initLayout(context);
        GridView gridView = mGridView;
        if (null == gridView) {
            gridView = getContentView(context, columns);
        } else {
            setContentViewListener(gridView);
        }

        layout.addView(gridView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));

        // TODO 对高度进行修正
        int h = 0;
        if (mAlign == MenuItem.TEXT_LEFT || mAlign == MenuItem.TEXT_RIGHT) {
            h = (int)(height * rows + 5 * density);
        } else if (mAlign == MenuItem.TEXT_BOTTOM || mAlign == MenuItem.TEXT_TOP) {
            h = (int)((height + 20 * density) * rows);
        }
        if (txtLength != 0) {
            h += 20 * density;
        }

        mPopup = new PopupWindow(context);
        mPopup.setWidth(width);
        mPopup.setHeight(mHeight == 0 ? h : mHeight);
        mPopup.setContentView(layout);
        mPopup.setFocusable(true);
        mPopup.setOutsideTouchable(true);
        mPopup.setTouchable(true);
        // 设置背景为null，就不会出现黑色背景，按返回键PopupWindow就会消失
        mPopup.setBackgroundDrawable(null);
        if (mAnimStyle != 0) {
            mPopup.setAnimationStyle(mAnimStyle);
        }
        mPopup.showAtLocation(layout, Gravity.BOTTOM | Gravity.LEFT, mLeftMargin,
                (int)(80 * density));
        return true;
    }

    private LinearLayout initLayout(Context context) {
        LinearLayout layout = new LinearLayout(context);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.setFadingEdgeLength(0);
        layout.setGravity(Gravity.CENTER);

        layout.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                if (event.getAction() == MotionEvent.ACTION_DOWN) {
                    hide();
                }
                return false;
            }

        });

        return layout;
    }

    /**
     * 初始数据，将数据加载到对应的View中
     */
    private void initData() {
        MenuItem item = new MenuItem(mContext);
        item.setTextAlign(mAlign);
        item.setTextColor(mTxtColor);
        item.setTextSize(mTxtColor);
        int txtLength = mTexts.length;
        int imgLength = mImgRes.length;
        if (txtLength != 0 && imgLength != 0) // 文字和图片同时存在
        {
            for (int i = 0; i < imgLength; i++) {
                MenuItem menuItem = new MenuItem(mContext, item);
                menuItem.setImageRes(mImgRes[i]);
                menuItem.setText(mTexts[i]);
                mMenuItems.add(menuItem);
            }

        } else {
            if (txtLength != 0) // 只有文字
            {
                for (int i = 0; i < txtLength; i++) {
                    MenuItem menuItem = new MenuItem(mContext, item);
                    menuItem.setText(mTexts[i]);
                    mMenuItems.add(menuItem);
                }
            } else if (imgLength != 0) // 只有图片
            {
                for (int i = 0; i < imgLength; i++) {
                    MenuItem menuItem = new MenuItem(mContext, item);
                    menuItem.setImageRes(mImgRes[i]);
                    mMenuItems.add(menuItem);
                }
            }
        }
    }

    /**
     * 初始化菜单内容组件
     * 
     * @param context
     * @param columns 菜单的列数
     * @return
     */
    private GridView getContentView(Context context, int columns) {
        if (mMenuItems.isEmpty()) {
            initData();
        }

        if (null != mGridView) {
            return mGridView;
        }
        GridView gridView = new GridView(context);
        gridView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        gridView.setAdapter(new MenuAdapter(mMenuItems));
        gridView.setVerticalSpacing(0);
        gridView.setNumColumns(columns);
        gridView.setGravity(Gravity.CENTER);
        gridView.setVerticalScrollBarEnabled(false);
        if (mBg != 0) {
            gridView.setBackgroundResource(mBg);
        }
        if (mSelector != -1) {
            gridView.setSelector(mSelector);
        }
        gridView.setHorizontalScrollBarEnabled(false);
        setContentViewListener(gridView);
        return gridView;
    }

    /**
     * 注册事件
     * 
     * @param gridView
     */
    private void setContentViewListener(GridView gridView) {
        if (null == gridView.getOnItemClickListener()) {
            gridView.setOnItemClickListener(new OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    if (null != mListener) {
                        mListener.onMenuItemClick(parent, view, position);
                    }

                    hide();
                }

            });
        }

        gridView.setOnKeyListener(new OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (event.getAction() == KeyEvent.ACTION_UP) {
                    switch (keyCode) {
                        case KeyEvent.KEYCODE_BACK:
                        case KeyEvent.KEYCODE_MENU:
                            hide();
                            break;
                    }
                }
                return false;
            }

        });
    }

    /**
     * 获取所有图片的最大的宽和高
     * 
     * @param imgRes
     * @return
     */
    private Point getImageMaxDimension(int[] imgRes) {
        final Point point = new Point();
        for (int i = 0, length = imgRes.length; i < length; i++) {
            Bitmap tmp = BitmapFactory.decodeResource(mContext.getResources(), imgRes[i]);
            int width = tmp.getWidth();
            int height = tmp.getHeight();
            tmp.recycle();
            tmp = null;
            if (point.x < width) {
                point.x = width;
            }
            if (point.y < height) {
                point.y = height;
            }
        }

        return point;
    }

    /**
     * 计算文本的最大长度
     * 
     * @param txts
     * @return
     */
    private Point getTextMaxDimenstion(String[] txts) {
        final Point point = new Point();
        final Rect bounds = new Rect();
        final Paint paint = new Paint();
        float size = mTxtSize != -1 ? mTxtSize
                : mContext.getResources().getDisplayMetrics().density * 16;
        paint.setTextSize(size);
        paint.setColor(mTxtColor != -1 ? mTxtColor : Color.BLACK);
        if (mIsOptimizeTxt) // 对文字长度进行限制
        {
            for (int i = 0, length = txts.length; i < length; i++) {
                String str = txts[i];
                if (null == str) {
                    str = "";
                } else if (str.length() > mMaxStrLength) {
                    // 对字符串长度进行控制
                    str = new StringBuilder().append(str.substring(0, mMaxStrLength)).append("...")
                            .toString();
                }

                txts[i] = str;
                paint.getTextBounds(str, 0, str.length(), bounds);
                compareDimension(point, bounds.width(), bounds.height());
            }
        } else // 对文字长度不做限制，此时要注意图片和文字同时存在时的最终宽度
        {
            for (int i = 0, length = txts.length; i < length; i++) {
                String str = txts[i];
                if (null == str) {
                    str = "";
                }

                txts[i] = str;
                paint.getTextBounds(str, 0, str.length(), bounds);
                compareDimension(point, bounds.width(), bounds.height());
            }
        }
        return point;
    }

    /**
     * 比较并改变最大尺寸
     * 
     * @param point 保存最大尺寸的对象
     * @param width 宽
     * @param height 高
     */
    private void compareDimension(Point point, int width, int height) {
        if (point.x < width) {
            point.x = width;
        }

        if (point.y < height) {
            point.y = height;
        }
    }

    /**
     * 隐藏菜单
     * 
     * @return 隐藏成功返回true，失败返回false
     */
    public boolean hide() {
        if (null != mPopup && mPopup.isShowing()) {
            mPopup.dismiss();
            mPopup = null;
            if (null != mListener) {
                mListener.hideMenu();
            }

            mIsShow = false;
            return true;
        }
        return false;
    }

    /**
     * 菜单是否是显示
     * 
     * @return
     */
    public boolean isShow() {
        return mIsShow;
    }

    public void dismiss() {
        mMenuItems.clear();
        mGridView = null;
        mTexts = new String[0];
        mImgRes = new int[0];
        mWidth = 0;
        mHeight = 0;
    }

    /**
     * 设置菜单项被选中监听器
     * 
     * @param listener
     */
    public void setOnMenuClickListener(OnMenuClickListener listener) {
        mListener = listener;
    }

}
